<?php

/**
 * Ignus Framework
 *
 * @author Sergey Palyanov <sergey.palyanov@gmail.com>
 * @link http://code.google.com/p/ignus-php/
 * @license http://apache.org/licenses/LICENSE-2.0
 * @package Ignus
 * @subpackage Log
 * @since 0.1
 */

namespace Ignus\Log;

use Ignus\Log\Append\Appender;

/**
 * @category Ignus
 * @package Log
 * @since 0.1
 */
class Logger
{
    // log levels
    const NONE  = 'NONE';
    const ERROR = 'ERROR';
    const WARN  = 'WARN';
    const INFO  = 'INFO';
    const DEBUG = 'DEBUG';
    const TRACE = 'TRACE';

    // log entry fields
    const ENTRY_SECONDS = 0;
    const ENTRY_MSEC    = 1;
    const ENTRY_LEVEL   = 2;
    const ENTRY_NAME    = 3;
    const ENTRY_MESSAGE = 4;

    /**
     * Log levels' names
     * @var array
     */
    private static $priorities = array(
        self::NONE  => 0,
        self::ERROR => 1,
        self::WARN  => 2,
        self::INFO  => 3,
        self::DEBUG => 4,
        self::TRACE => 5,
    );

    /**
     * Logger name
     * @var string
     */
    private $name;

    /**
     * @var LogManager Manager
     */
    private $manager;

    /**
     * Creates logger object
     * @param \Ignus\Log\LogManager $manager
     * @param string $name Logger name
     */
    public function __construct(LogManager $manager, $name)
    {
        $this->manager = $manager;
        $this->name = $name;
    }

    /**
     * Add log entry with specified logging level
     * @param string $level Logging level
     * @param array $message Log string parts
     */
    private function appendLog($level, array $message)
    {
        if (self::$priorities[$this->manager->level()] < self::$priorities[$level])
            return;

        $message = count($message) > 1 ? call_user_func_array('sprintf', $message) : $message[0];
        if ($message instanceof \Exception) {
            $message = 'Exception \'' . $message->getMessage()
                . '\' thrown at ' . $message->getFile() . ':' . $message->getLine();
        }

        list($microseconds, $seconds) = explode(' ', microtime());
        $this->manager->addEntry(array(
            self::ENTRY_SECONDS =>  $seconds,
            self::ENTRY_MSEC    =>  $microseconds,
            self::ENTRY_LEVEL   =>  $level,
            self::ENTRY_NAME    =>  $this->name,
            self::ENTRY_MESSAGE =>  $message,
        ));
    }

    /**
     * Add log entry with ERROR logging level
     * @param string $str String to log
     */
    public function error($str)
    {
        $this->appendLog(self::ERROR, func_get_args());
    }

    /**
     * Add log entry with WARN logging level
     * @param string $str String to log
     */
    public function warn($str)
    {
        $this->appendLog(self::WARN, func_get_args());
    }

    /**
     * Add log entry with INFO logging level
     * @param string $str String to log
     */
    public function info($str)
    {
        $this->appendLog(self::INFO, func_get_args());
    }

    /**
     * Add log entry with DEBUG logging level
     * @param string $str String to log
     */
    public function debug($str)
    {
        $this->appendLog(self::DEBUG, func_get_args());
    }

    /**
     * Add log entry with TRACE logging level
     * @param string $str String to log
     */
    public function trace($str)
    {
        $this->appendLog(self::TRACE, func_get_args());
    }

    /**
     * Returns true if $str is logging level
     * @static
     * @param string $str String to test
     * @return boolean
     * @since 0.3
     */
    public static function isLevel($str)
    {
        return isset(self::$priorities[$str]);
    }
}
